using Sidvall.Collections;
using Sidvall.Data;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;

namespace Sidvall.UI.Entities
{
    public sealed class TreeItemCollection : BusinessBaseCollection<TreeItem>
    {
        #region Public Members

        #region TotalChildCount

        public int TotalChildCount
        {
            get
            {
                int count;

                count = this.Count;
                foreach (var item in this)
                    count += item.TotalChildCount;

                return count;
            }
        }

        #endregion

        #region AcceptChanges

        public void AcceptChanges()
        {
            AcceptChanges(null);
        }
        public void AcceptChanges(Sidvall.Data.AcceptChangesSettings acceptChangesSettings)
        {
            this.DeletedItemKeys.Clear();
            foreach (var item in this)
                item.AcceptChanges(acceptChangesSettings);
        }

        #endregion
        #region Add

        public TreeItem Add(string id, string name, string parentId, int displayPosition)
        {
            return Add(id, name, parentId, displayPosition, true, null);
        }
        public TreeItem Add(string id, string name, string parentId, int displayPosition, bool isSelected)
        {
            return Add(id, name, parentId, displayPosition, isSelected, null);
        }
        public TreeItem Add(string id, string name, string parentId, int displayPosition, bool isSelected, object dataItem)
        {
            var item = TreeItem.CreateTreeItem(id, name, parentId, displayPosition, isSelected, dataItem);
            Add(item);
            return item;
        }
        public TreeItem Add(string id, string name, string parentId, int displayPosition, bool isSelected, object dataItem, string groupName, string code, string description)
        {
            var item = TreeItem.CreateTreeItem(id, name, parentId, displayPosition, isSelected, dataItem, groupName, code, description);
            Add(item);
            return item;
        }

        #endregion
        #region AddItems

        public void AddItems(IEnumerable<IItem> items, string parentId)
        {
            int displayPosition;

            if (items == null)
                return;
            if (this.Count > 0)
            {
                displayPosition = (from o in this
                                   select o.DisplayPosition).Max() + 1;
            }
            else
            {
                displayPosition = 1;
            }
            using (var businessCollectionEventManager = new Sidvall.Business.BusinessCollectionSettingsManager(this, Sidvall.Business.BusinessCollectionSettings.CreateSettingsNone()))
            {
                foreach (var item in items)
                {
                    Add(item.Id, item.Name, parentId, displayPosition, true, item);
                    displayPosition += 1;
                }
                OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
            }
        }

        #endregion
        #region Clone

        public TreeItemCollection Clone()
        {
            var copySettings = Sidvall.Data.CopySettings.Clone();
            return Copy(copySettings);
        }

        #endregion
        #region Copy

        public TreeItemCollection Copy()
        {
            return Copy(null);
        }
        public TreeItemCollection Copy(Sidvall.Data.CopySettings copySettings)
        {
            var items = new TreeItemCollection();
            items.Import(this, copySettings);
            return items;
        }

        #endregion
        #region Import

        public void Import(IEnumerable<TreeItem> items)
        {
            Import(items, null);
        }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        public void Import(IEnumerable<TreeItem> items, Sidvall.Data.CopySettings copySettings)
        {
            TreeItem item;
            Sidvall.Business.BusinessCollectionSettings businessSettings;

            if (items == null)
                return;
            if (copySettings == null)
                copySettings = new Sidvall.Data.CopySettings();
            else if (copySettings.MergeOption == Sidvall.Data.MergeOption.DoNothing)
                return;
            if (copySettings.RaisePropertyChanged)
                businessSettings = Sidvall.Business.BusinessCollectionSettings.CreateSettingsAll();
            else
                businessSettings = Sidvall.Business.BusinessCollectionSettings.CreateSettingsNone();
            var sourceListContextProvider = items as Sidvall.Data.IListContextProvider;
            using (var businessCollectionEventManager = new Sidvall.Business.BusinessCollectionSettingsManager(this, businessSettings))
            {
                switch (copySettings.MergeOption)
                {
                    case Sidvall.Data.MergeOption.Merge:
                        var index = items.ToDictionary(o => o.Id, true, false);
                        var deletedItems = new List<TreeItem>();
                        var updatedItemIndex = new HashSet<string>();

                        // Update & Delete
                        foreach (var destinationItem in this)
                        {
                            var key = destinationItem.Id;
                            if ((key != null) && (index.TryGetValue(key, out item)))
                            {
                                destinationItem.Import(item, copySettings);
                                updatedItemIndex.Add(key);
                            }
                            else if (destinationItem.DataRowStateIsDeleted)
                            {
                                deletedItems.Add(destinationItem);
                            }
                            else if ((sourceListContextProvider != null) && (sourceListContextProvider.DeletedItemKeys.Contains(key)))
                            {
                                deletedItems.Add(destinationItem);
                            }
                        }
                        foreach (var deletedItem in deletedItems)
                            Remove(deletedItem);

                        // Add
                        foreach (var sourceItem in index.Values)
                        {
                            if ((sourceItem.Id != null) && (updatedItemIndex.Contains(sourceItem.Id)))
                                continue;
                            item = sourceItem.Copy(copySettings);
                            if (item != null)
                                Add(item);
                        }
                        break;
                    case Sidvall.Data.MergeOption.Append:
                        foreach (var sourceItem in items)
                        {
                            item = sourceItem.Copy(copySettings);
                            if (item != null)
                                Add(item);
                        }
                        if (copySettings.RowFilter.HasFlag(Sidvall.Data.DataRowFilters.Deleted))
                        {
                            if (sourceListContextProvider != null)
                            {
                                foreach (var sourceItemKey in sourceListContextProvider.DeletedItemKeys)
                                    this.DeletedItemKeys.Add(sourceItemKey);
                            }
                        }
                        break;
                    default:
                        break;
                }
                var sourceTotalRowCount = items as Sidvall.Data.ITotalRowCount;
                if (sourceTotalRowCount != null)
                {
                    this.TotalRowCount = sourceTotalRowCount.TotalRowCount;
                }
                OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
            }
        }

        #endregion

        #endregion
        #region Private Members

        #region PropagateDownSelected

        internal void PropagateDownSelected(bool isSelected, bool raisePropertyChanged, bool updateState)
        {
            int iMax = this.Count;
            for (int i = 0; i < iMax; i++)
                this[i].PropagateDownSelected(isSelected, raisePropertyChanged, updateState, true);
        }

        #endregion
        #region PropagateDownVisible

        internal void PropagateDownVisible(bool isVisible, bool raisePropertyChanged, bool updateState)
        {
            int iMax = this.Count;
            for (int i = 0; i < iMax; i++)
                this[i].PropagateDownVisible(isVisible, raisePropertyChanged, updateState, true);
        }

        #endregion

        #endregion
        #region Constructors

        public TreeItemCollection()
        {
        }

        #endregion
    }
}
